package com.easwift.qsp.das.pool;

import com.easwift.qsp.util.BitUtils;
import com.easwift.qsp.util.CRCUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 数据池
 * @author Administrator
 *
 */
public class DataPool {

	private String head;// 帧头 目前设置的是def7

	private int frameLength;// 一帧的长度，固定的

	private int dataLength;// 帧的数据内容长度，固定的

	private int crcOneLength;// 第一个CRC计算数据长度  8

	private boolean lookupBefore;// 是否往前查找，true往前false往后  true

	private boolean getAll;// 是否取到所有帧，true是false取一帧  true

	private StringBuffer data;// 16进制数据字符串

	/**
	 * 初始化数据池
	 *
	 * @return
	 */
	public DataPool init() {
		if (data == null) {
			data = new StringBuffer();
		}
		return this;
	}

	/**
	 * 数据池中添加数据
	 *
	 * @return
	 */
	public void add(byte[] data) {
		if (data != null) {
			init();
			this.data.append(BitUtils.byteArrayToHexString(data));
		}
	}

	/**
	 * 数据池中取得所有完整一帧数据
	 *
	 * @return
	 */
	public List<byte[]> get() {
		if (data == null) {
			return null;
		}
		List<byte[]> list = new ArrayList<>(1);
		// 帧头的位置，取最新的一条也就是从后加入的池数据中取
		int index = data.lastIndexOf(head);
		// 如果能找到帧头，进行循环
		while (index > -1) {
			// 如果最后一帧不是断的
			if (index + (frameLength - 2) * 2 <= data.length()) {

				String frameString = data.substring(index - 4, index + (frameLength - 2) * 2);
				byte[] frame = BitUtils.hexStringToByteArray(frameString);
				byte[] crcData1 = new byte[crcOneLength];
				System.arraycopy(frame, 4, crcData1, 0, crcOneLength);
				int[] crc1 = CRCUtils.genCrc(crcData1, crcData1.length);
				// 如果crc1通过，继续判断crc2
				if (crc1[0] == Byte.toUnsignedInt(frame[4 + crcOneLength]) && crc1[1] == Byte.toUnsignedInt(frame[5 + crcOneLength])) {
					byte[] crcData2 = new byte[dataLength];
					System.arraycopy(frame, 6 + crcOneLength, crcData2, 0, dataLength);
					int[] crc2 = CRCUtils.genCrc(crcData2, crcData2.length);
					// 如果crc2也通过，则取出来的是完整一帧
					if (crc2[0] == Byte.toUnsignedInt(frame[frameLength - 2]) && crc2[1] == Byte.toUnsignedInt(frame[frameLength - 1])) {
						// 将完整的一帧加入list
						list.add(frame);
						// 查找策略。如果是往前查找
						if (lookupBefore) {
							// 丢弃帧后面的数据，防止内存溢出
							discardBehind(index - 4);
							// 继续往前面找其它帧头（注此处的数据池已经是没有最前两位地址的所以不能和下面放一起会报arrayIndexOutOfbounds）
							index = data.lastIndexOf(head);
						} else {
							// 丢弃帧前面的数据
							discard(index + (frameLength - 2) * 2);
						}
						if (getAll) {
							continue;
						} else {
							break;
						}
					}
				}
			}
			// 如果最后一帧是断帧，或者不是完整一帧，继续往前面找帧头
			// 这里要保留dataindex后面的数据，因为后面可能出现帧尾
			String dString = data.substring(0, index);
			index = dString.lastIndexOf(head);
		}
		return list;
	}

	/**
	 * 丢弃数据池中index前面的数据
	 *
	 * @return
	 */
	public void discard(int index) {
		data.replace(0, index, "");
	}

	/**
	 * 丢弃数据池中index后面的数据
	 *
	 * @param index
	 */
	public void discardBehind(int index) {
		data.replace(index, data.length(), "");
	}

	public void setHead(String head) {
		this.head = head;
	}

	public void setFrameLength(int frameLength) {
		this.frameLength = frameLength;
	}

	public void setDataLength(int dataLength) {
		this.dataLength = dataLength;
	}

	public void setCrcOneLength(int crcOneLength) {
		this.crcOneLength = crcOneLength;
	}

	public void setLookupBefore(boolean lookupBefore) {
		this.lookupBefore = lookupBefore;
	}

	public void setGetAll(boolean getAll) {
		this.getAll = getAll;
	}

}
